package com.dashan.servlets;

import static com.dashan.Constants.*;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.servlet.ServletException;

import com.dashan.backend.AccessControlManager.Permission;
import com.google.appengine.repackaged.com.google.common.base.StringUtil;

@SuppressWarnings("unchecked")
public class Parameter {
    public enum Option {
        Required,
        Optional,
        HasDefaultValue,
    }
    
    private String name;
    private Option option;
    private String rawValue;
    private Class type;
    private String description;
    private boolean hasValue = false;
    
    public Parameter(String name, Option option, Class type) {
        this.name = name;
        this.option = option;
        this.type = type; 
    }
    
    public Parameter(String name, Option option, Class type, String desc) {
        this(name, option, type);
        this.description = desc;
    }
    
    /** Will be set as HasDefaultValue type. */
    public Parameter(String name, Class type, String defaultValue) {
        this(name, Option.HasDefaultValue, type);
        this.rawValue = defaultValue;
    }
    
    /** Will be set as HasDefaultValue type. */
    public Parameter(String name, Class type, String defaultValue, String desc) {
        this(name, type, defaultValue);
        this.description = desc;
    }
    
    public boolean isDouble() {
        return (type == Double.class || type == double.class);
    }
    
    public boolean isInteger() {
        return (type == Integer.class || type == int.class);
    }
    public boolean isLong() {
        return (type == Long.class || type == long.class);
    }
    
    public boolean isDate() {
        return (type == Date.class);
    }
    
    public boolean isString() {
        return (type == String.class);
    }
    
    public boolean isPermission() {
        return (type == Permission.class);
    }
    
    public boolean isBoolean() {
        return (type == boolean.class || type == Boolean.class);
    }
    
    protected boolean validateValue() {
        if (isDouble() && doubleValue() == null) {
            return false;
        } 
        if (isString() && stringValue() == null) {
            return false;
        }
        if (isDate() && dateValue() == null) {
            return false;
        }
        if (isInteger() && integerValue() == null) {
            return false;
        }
        if (isLong() && longValue() == null) {
            return false;
        }
        if (isPermission() && permissionSetValue() == null) {
            return false;
        }
        if (isBoolean() && booleanValue() == null) {
            return false;
        }
        return true;
    }
    
    public void setRawValue(String stringValue) throws ServletException {
        this.rawValue = stringValue;
        this.hasValue = true;
        if (!validateValue()) {
            throw new ServletException("Invalid parameter value for " + name + ": " + rawValue);
        }
    }
    
    public String getDefaultValue() {
        if (option == Option.HasDefaultValue) {
            return rawValue;
        } else {
            return "";
        }
    }
    
    public Double doubleValue() {
        if (isDouble()) {
            try {
                return Double.parseDouble(rawValue);
            } catch (NumberFormatException e) {
                return null;
            }
        } else {
            return null;
        }
    }
    
    public Integer integerValue() {
        if(isInteger()) {
            try {
                return Integer.parseInt(rawValue);
            } catch (NumberFormatException e) {
                return null;
            }
        } else {
            return null;
        }
    }
    
    public Long longValue() {
        if(isLong()) {
            try {
                return Long.parseLong(rawValue);
            } catch (NumberFormatException e) {
                return null;
            }
        } else {
            return null;
        }
    }
    
    public Date dateValue() {
        if (isDate()) {
            try {
                Date d = new Date(Long.parseLong(rawValue));
                return d;
            } catch (NumberFormatException e) {
                return null;
            }
        } else {
            return null;
        }
    }
    
    public String stringValue() {
        if (isString()) {
            return rawValue;
        } else {
            return null;
        }
    }
    
    public Set<Permission> permissionSetValue() {
        if (isPermission() && !StringUtil.isEmptyOrWhitespace(rawValue)) {
            String[] permissionNames = rawValue.split(SEPERATOR);
            Set<Permission> pSet = new HashSet<Permission>(); 
            for (String pName : permissionNames) {
                pName = pName.trim();
                Permission p = Permission.get(pName);
                if (p == null) {
                    return null;
                } else {
                    pSet.add(p);
                }
            }
            return pSet;
        } else {
            return null;
        }
    }
    
    public Boolean booleanValue() {
        if (isBoolean()) {
            if (rawValue.compareTo(TRUE) == 0) {
                return true;
            } else if (rawValue.compareTo(FALSE) == 0) {
                return false;
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    public String getName() {
        return name;
    }

    public Option getOption() {
        return option;
    }

    public boolean hasValue() {
        return hasValue;
    }

    public String getDescription() {
        return description;
    }
}
